package lol.clann.minecraft.springboot.plugin.core.database.mybatis;

import com.ruoshui.utils.java.spi.SPIUtils;
import lol.clann.minecraft.springboot.api.context.PluginContext;
import lol.clann.minecraft.springboot.api.context.SpringContext;
import lol.clann.minecraft.springboot.api.model.core.Plugin;
import lol.clann.minecraft.springboot.api.spi.mybatis.TypeHandlerProvider;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * 如果有数据源
 * 就会启用mybatis
 * xml mapper放在 包路径下任意mapper目录内
 * java mapper放在包路径下任意mapper包内
 *
 * @author pyz
 * @date 2019/4/15 4:57 PM
 */
@Slf4j
@Configuration
@ConditionalOnBean(DataSource.class)
public class ImportMybatisBean {
    public static final String MYBATIS_CONFIG_LOCATION = "sbp/config/mybatis-config.xml";

    @Bean(name = "sqlSessionFactory")
    public static SqlSessionFactory sqlSessionFactory(@Autowired DataSource dataSource) throws Exception {
        final SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        List<Resource> resources = new ArrayList<>();
        for (Plugin plugin : PluginContext.getPlugins()) {
            Set<String> basePackages = plugin.getBasePackages();
            if (basePackages == null) {
                continue;
            }
            for (String basePackage : basePackages) {
                Resource[] resource = resolver.getResources("classpath*:" + basePackage.replace('.', '/') + "/**/mapper/*.xml");
                for (Resource r : resource) {
                    resources.add(r);
                    LOGGER.info("find xml mapper in plugin {}:{}", plugin.getId(), r.toString());
                }
            }
        }
        sqlSessionFactoryBean.setMapperLocations(resources.toArray(new Resource[resources.size()]));
        sqlSessionFactoryBean.setConfigLocation(new ClassPathResource(ImportMybatisBean.MYBATIS_CONFIG_LOCATION));
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBean.getObject();
        TypeHandlerRegistry r = sqlSessionFactory.getConfiguration().getTypeHandlerRegistry();
        for (Class<? extends TypeHandlerProvider> typeHandlerProviderClass : SPIUtils.loadClass(TypeHandlerProvider.class)) {
            TypeHandlerProvider typeHandlerProvider = SpringContext.createBean(typeHandlerProviderClass);
            LOGGER.info("register typehandler.class={},typeHandlerClass={}", typeHandlerProvider.getHandledClass().getName(), typeHandlerProvider.getClass().getName());
            r.register(typeHandlerProvider.getHandledClass(), typeHandlerProvider);
        }
        return sqlSessionFactory;
    }
}
